<template>
  <div class="table_form_wrap">
    <el-row>
      <el-form
        :ref="refName"
        :model="formData"
        :inline="isInline"
        :disabled="allDisabled"
        @submit.native.prevent
      >
        <el-row v-for="(rowNum, rowIndex) in totalRowNum" :key="rowIndex">
          <el-col
            v-for="(item, index) in formItemList.slice(
              rowIndex * colNumOfRow,
              rowNum * colNumOfRow
            )"
            :key="item.prop + index"
            :span="24 / colNumOfRow"
          >
            <el-form-item
              :prop="item.prop"
              :label="`${showColon ? `${item.label}：` : item.label}`"
              :label-width="item.width || formItemWidth"
            >
              <!-- 普通输入框 -->
              <template v-if="item.type === 'input'">
                <el-input
                  v-model.trim="formData[item.prop]"
                  :placeholder="item.placeholder || `请输入${item.label}`"
                  :disabled="item.disabled"
                  @keyup.enter.native="handleQueryForm"
                />
              </template>
              <!-- 普通下拉框 -->
              <template v-else-if="item.type === 'select'">
                <el-select
                  ref="elSelect"
                  collapse-tags
                  v-model="formData[item.prop]"
                  style="width: 100%"
                  :multiple="item.multiple"
                  :filterable="item.remote || item.filterable"
                  :filter-method="item.filterMethod"
                  :placeholder="item.placeholder || `请选择${item.label}`"
                  :disabled="item.disabled"
                  :clearable="item.clearable"
                  :remote="item.remote"
                  :remote-method="(val) => { handleRemoteSelect(val, item) }"
                  :reserve-keyword="item.reserveKeyword"
                  :loading="selectRemoteLoading[item.prop]"
                  :multiple-limit="item.multipleLimit"
                  :allow-create="item.allowCreate"
                  @change="val => { handleChangeSelect(val, item) }"
                >
                  <el-option
                    v-for="option in getSelectOptions(item)"
                    :key="getSelectOptionKeys(option, item).key"
                    :label="getSelectOptionKeys(option, item).label"
                    :value="getSelectOptionKeys(option, item).value"
                    :disabled="isOptionDisabled(option, item)"
                  />
                </el-select>
              </template>
              <!-- 日期时间选择器 -->
              <template v-else-if="item.type === 'datePicker'">
                <!--
                  @datePickerType
                  默认不传为 daterange 日期选择器
                  datetimerange 为时间日期选择器
                  其余格式：year/month/date/dates/ week/datetime/monthrange
                -->
                <el-date-picker
                  v-model="formData[item.prop]"
                  :type="item.datePickerType || 'daterange'"
                  :title="dateTitle"
                  style="width: 100%"
                  :value-format="item.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
                  :range-separator="item.rangeSeparator || '-'"
                  :start-placeholder="item.startPlaceholder || '开始日期'"
                  :end-placeholder="item.endPlaceholder || '结束日期'"
                  :placeholder="item.placeholder || `请选择${item.label}`"
                  :disabled="item.disabled"
                  :default-time="item.defaultTime || ['00:00:00', '23:59:59']"
                  :unlink-panels="true"
                  :pickerOptions="item.pickerOptions"
                  @change="val => { handleSelectDatePicker(val, item) }"
                />
              </template>
              <template v-else-if="item.type === 'date'">
                <el-date-picker
                  v-model="formData[item.prop]"
                  value-format="yyyy-MM-dd"
                  type="date"
                  :placeholder="item.placeholder || `请选择${item.label}`"
                  :pickerOptions="item.pickerOptions"
                >
                </el-date-picker>
              </template>
              <!-- 范围查询 -->
              <template v-else-if="item.type === 'range'">
                <el-col :span="11">
                  <el-form-item :prop="item.props[0]" class="inner-form-item">
                    <InputNumber :controls="false" v-if="item.rangeType == 'inputNum'" v-model="formData[item.props[0]]" :precision="item.precision" style="width: 100%;" />
                    <el-input v-else v-model="formData[item.props[0]]" style="width: 100%;" />
                  </el-form-item>
                </el-col>
                <el-col class="line" :span="2">-</el-col>
                <el-col :span="11">
                  <el-form-item :prop="item.props[1]" class="inner-form-item">
                    <InputNumber :controls="false" v-if="item.rangeType == 'inputNum'" v-model="formData[item.props[1]]" :precision="item.precision" style="width: 100%;" />
                    <el-input v-else v-model="formData[item.props[1]]" style="width: 100%;" />
                  </el-form-item>
                </el-col>
              </template>
              <!-- 自定义搜索条件下拉框 -->
              <template v-else-if="item.type === 'selectFilter'">
                <el-select
                  v-model="formData[item.prop]"
                  style="width: 100%"
                  :multiple="item.multiple"
                  :filterable="item.filterable"
                  :filter-method="(query) => handleFilterOptions(query, item)"
                  :placeholder="item.placeholder || `请输入${item.label}`"
                  :disabled="item.disabled"
                  :clearable="item.clearable"
                  collapse-tags
                >
                  <el-option
                    v-for="item in item.options"
                    :key="item.value || item.authDepartmentNo"
                    :label="item.label || item.authDepartmentName"
                    :value="item.value || item.authDepartmentNo"
                  />
                </el-select>
              </template>
              <template v-else-if="item.type === 'slot'">
                <slot :name="item.slotName || item.prop"></slot>
              </template>
              <template v-else>
                <span>{{ formData[item.prop] }}</span>
              </template>
            </el-form-item>
          </el-col>
          <template v-if="formItemList.length < colNumOfRow * (rowIndex + 1) && !isBtnBarSingleRow && showBtnBar">
            <el-row type="flex" :justify="actionPosition" :style="btnBarStyle">
              <BtnRender :render="actionRender" />
              <slot name="extensionActions" />
            </el-row>
          </template>
        </el-row>
      </el-form>
    </el-row>
    <el-row
      v-if="(formItemList.length === totalRowNum * colNumOfRow || isBtnBarSingleRow) && showBtnBar"
      type="flex"
      :justify="actionPosition"
      :style="btnBarStyle"
    >
      <slot name="action">
        <BtnRender :render="actionRender" />
      </slot>
      <slot name="extensionActions" />
    </el-row>
  </div>
</template>
<script>
import { mapGetters } from 'vuex';
import BtnRender from './BtnRender';
import InputNumber from '@/components/inputNumber/inputNumber'
import { setAuthBtnId } from '@/utils/bizUtils';

export default {
  props: {
    formColumns: { // 表单item名集合
      type: Array,
      default () {
        return [];
      }
    },
    dataSource: { // 表单formData
      type: Object,
      default () {
        return {};
      }
    },
    formItemWidth: { // 表单item默认宽度
      type: String,
      default: '100px'
    },
    isInline: { // 表单是否开启inline模式
      type: Boolean,
      default: false
    },
    colNumOfRow: { // 表单每行col数量
      type: Number,
      default: 3
    },
    handleSearchForm: { // 查询方法
      type: Function
    },
    handleClearForm: { // 清空方法
      type: Function
    },
    searchBtnRender: { // 查询按钮（外部需要特殊渲染所用）
      type: Function
    },
    resetBtnRender: { // 清空按钮（外部需要特殊渲染所用）
      type: Function
    },
    searchBtnName: { // 查询按钮名称
      type: String,
      default: '查询'
    },
    resetBtnName: { // 清空按钮名称
      type: String,
      default: '清空'
    },
    isResetToQuery: { // 清空表单是否同时调用查询事件
      type: Boolean,
      default: false
    },
    refName: { // 表单ref名
      type: String,
      default: 'formData'
    },
    actionPosition: { // 表单操作按钮栏位置
      type: String,
      default: 'end'
    },
    allDisabled: { // 表单是否开启禁用
      type: Boolean,
      default: false
    },
    isScalingBtn: { // 是否展示收起或展开按钮
      type: Boolean,
      default: true
    },
    defaultExpandStatus: { // true为展开状态，按钮为收起；false为收起状态，按钮为展开
      type: Boolean,
      default: false
    },
    isBtnBarSingleRow: { // 按钮操作栏是否单独一行
      type: Boolean,
      default: false
    },
    hasQueryPermission: { // 是否需要查询按钮添加权限判断，默认添加
      type: Boolean,
      default: true
    },
    optionDisabledMethod: { // select单个option是否禁用方法
      type: Function
    },
    btnBarStyle: { // 按钮栏样式
      type: String
    },
    showBtnBar: { // 是否展示按钮栏
      type: Boolean,
      default: true
    },
    showColon: { // 是否展示标签冒号
      type: Boolean,
      default: false
    },
    remoteMethod: {
      type: Function,
      default: () => {}
    }
  },
  components: {
    BtnRender,
    InputNumber
  },
  data () {
    const remoteOptions = this.getRemoteOptions();
    return {
      formData: this.dataSource,
      formItemList: this.formColumns,
      expandStatus: this.defaultExpandStatus,
      selectRemoteLoading: {},
      remoteOptions
    };
  },
  mounted () {
    if (!this.defaultExpandStatus) {
      this.handlePackUp();
    }
  },
  computed: {
    ...mapGetters('permissions/systemBtns', ['showBtn']),
    /* 总行数 */
    totalRowNum () {
      return Math.ceil(this.formItemList.length / this.colNumOfRow);
    },
    /* 日期选择器title */
    dateTitle () {
      let target = this.formItemList.find((item) => {
        return item.type === 'datePicker';
      });
      if (!target) {
        return '';
      }
      if (!this.formData[target.prop]) {
        return '';
      }
      if (target.datePickerType === 'date') {
        return '';
      }
      return this.formData[target.prop].join(' - ');
    }
  },
  watch: {
    formData: {
      handler (newVal) {},
      immediate: true,
      deep: true
    },
    dataSource: {
      handler (newVal) {
        this.formData = newVal
      },
      immediate: true,
      deep: true
    },
    formColumns: {
      handler (val) {
        this.formItemList = val
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    // 获取远程搜索下拉options
    getRemoteOptions () {
      const options = this.formColumns.reduce((value, item) => {
        if (item.type === 'select' && item.remote) {
          value[item.prop] = [];
        }
        return value
      }, {});
      return options;
    },
    // 获取下拉option相关属性key
    getSelectOptionKeys (option, item) {
      const defaultKeys = { valueKey: 'value', labelKey: 'label', optionKey: 'value' };
      const { valueKey, labelKey, optionKey, codeKey } = item?.optionKeys ?? defaultKeys;
      const options = {
        value: option[valueKey],
        label: codeKey? `${option[labelKey]}(${option[codeKey]})` : option[labelKey],
        key: option[optionKey]
      }
      return options;
    },
    // select下拉款单个option是否禁用方法
    isOptionDisabled (option, item) {
      if (!this.optionDisabledMethod) { return false; }
      return this.optionDisabledMethod({ option, item });
    },
    // 获取select下拉options集合
    getSelectOptions (item) {
      const { remote, options, prop } = item;
      return remote ? this.remoteOptions[prop] : options;
    },
    // select下拉远程请求
    async handleRemoteSelect (val, item) {
      if (!val) {
        this.remoteOptions[item.prop] = [];
        return false;
      }
      const getDataAndMethod = () => {
        const params = { [item.paramKey]: val, ...item.extraParams }
        if (item.remoteMethod) return [item.remoteMethod, params]
        return [this.remoteMethod, val]
      }
      const [remoteMethod, data] = getDataAndMethod()
      const loadingFn = state => { this.selectRemoteLoading[item.prop] = state };
      const res = await remoteMethod(data, loadingFn);
      if (Array.isArray(res)) {
        return this.remoteOptions[item.prop] = res
      }
      if (Array.isArray(res?.retData)) {
        return this.remoteOptions[item.prop] = res.retData
      }
      if (Array.isArray(res?.retData?.results)) {
        return this.remoteOptions[item.prop] = res.retData.results
      }
    },
    // 下拉change
    handleChangeSelect (val, item) {
      this.$emit(`change-${item.prop}`, { val, formItem: item })
    },
    // 按钮控制栏有额外插槽按钮内容
    hasSlotByExtensionAction () {
      return Object.keys(this.$slots).length !== 0;
    },
    // 获取查询按钮栏类名
    getClassNameBySearchBtnBar () {
      return this.hasSlotByExtensionAction() ? 'table-action' : '';
    },
    /* 获取表单数据 */
    getFormDataFunc () {
      return this.formData;
    },
    /* 查询表单数据 */
    handleQueryForm (actionBtnName) {
      /* 如果没有name，就默认是查询按钮 */
      if (this.hasQueryPermission) {
        setAuthBtnId(actionBtnName ?? this.searchBtnName)
      }
      this.$emit('getFormData', this.formData, this.remoteOptions);
      this.$emit('getRemoteOptions', this.remoteOptions)
      /* 如果有外部传入的查询方法，就进行调用 */
      if (this.handleSearchForm) {
        this.handleSearchForm(this.formData);
      }
    },
    /* 清空表单数据 */
    handleResetForm () {
      this.$refs[this.refName].resetFields();
      // 清空formData
      this.formColumns.forEach(item => {
        this.$set(this.formData, item.prop, item.defaultValue ?? undefined)
      })
      this.clearRangedateVal() // 清空有时间范围的格式化时间值
      /* 如果有外部传入的清空方法，就进行调用 */
      if (this.handleClearForm) {
        this.handleClearForm();
      }
      /* 如果开启清空同时查询功能，就调用查询事件方法 */
      if (this.isResetToQuery) {
        this.handleQueryForm();
      }
      // 针对用户下拉单独处理
      this.$nextTick(() => {
        if (this.$refs.userSelect) {
          this.$refs.userSelect.forEach(item => {
            item.resetSelectVal()
          })
        }
      })
    },
    /* 收起表单事件 */
    handlePackUp () {
      this.expandStatus = false;
      this.formItemList = this.formColumns.reduce((value, item, index) => {
        if (index < this.colNumOfRow) {
          value.push(item);
        }
        return value;
      }, []);
    },
    /* 展开表单事件 */
    handleOpenUp () {
      this.expandStatus = true;
      this.formItemList = this.formColumns;
    },
    // 收起按钮
    packUpBtnFn () {
      return (<el-button
        type="text"
        icon="el-icon-arrow-up"
        onClick={() => { this.handlePackUp(); }}
      >收起</el-button>);
    },
    // 展开按钮
    openUpBtnFn () {
      return (<el-button
        type="text"
        icon="el-icon-arrow-down"
        onClick={() => { this.handleOpenUp(); }}
      >展开</el-button>);
    },
    // 查询按钮
    searchBtnFn () {
      // 如果开启权限，且没有查询按钮权限，就返回空标签
      if (this.hasQueryPermission && !this.showBtn(this.searchBtnName)) {
        return <div></div>;
      }
      // 如果有特殊渲染，返回特殊渲染的按钮
      if (this.searchBtnRender) {
        return this.searchBtnRender();
      }
      return (<el-button
        type="primary"
        nativeOnClick={() => { this.handleQueryForm(); }
      }
      >{this.searchBtnName}
      </el-button>);
    },
    // 清空按钮
    resetBtnFn () {
      // 如果有特殊渲染，返回特殊渲染的按钮
      if (this.resetBtnRender) {
        return this.resetBtnRender();
      }
      return (<el-button
        onClick={() => { this.handleResetForm(); }}
      >{this.resetBtnName}
      </el-button>);
    },
    actionRender (h) {
      const packUpBtn = this.packUpBtnFn();
      const openUpBtn = this.openUpBtnFn();
      const searchBtn = this.searchBtnFn();
      const resetBtn = this.resetBtnFn();
      let packOrOpenBtn = <div></div>;
      const isOnlyOneRow = this.formColumns.length / this.colNumOfRow <= 1 // 只有一行筛选项时，默认不展示展开收起按钮
      if (!this.isInline && this.isScalingBtn && !isOnlyOneRow) {
        packOrOpenBtn = this.expandStatus ? packUpBtn : openUpBtn;
      }
      return (
        <div class={this.getClassNameBySearchBtnBar()}>
          {packOrOpenBtn}
          {searchBtn}
          {resetBtn}
        </div>
      );
    },
    handleFilterOptions (query = '', obj) {
      let arr = obj.allOptions.filter(item => {
        return item.authDepartmentName.includes(query);
      });
      if (arr.length > 30) {
        obj.options = arr.slice(0, 30);
      } else {
        obj.options = arr;
      }
    },
    // 时间选择change事件
    handleSelectDatePicker (dateVal, formItem) {
      const rangeKeys = [undefined, 'daterange', 'datetimerange'] //
      if (!rangeKeys.includes(formItem.datePickerType)) return
      const [startTime = '', endTime = ''] = dateVal ?? []
      const [startKey = `${formItem.prop}Start`, endKey = `${formItem.prop}End`] = formItem?.timeKeys ?? []
      this.formData[startKey] = startTime
      this.formData[endKey] = endTime
    },
    // 清除范围日期值
    clearRangedateVal () {
      const rangeKeys = [undefined, 'daterange', 'datetimerange']
      const daterangeItems= this.formColumns
        .filter(item => item.type == 'datePicker' && rangeKeys.includes(item.datePickerType))
      if (daterangeItems.length == 0) return
      daterangeItems.forEach(item => {
        const [startKey = `${item.prop}Start`, endKey = `${item.prop}End`] = item?.timeKeys ?? []
        this.formData[startKey] = ''
        this.formData[endKey] = ''
      })
    },
  }
};
</script>
<style lang="less" scoped>
/deep/ .el-range-input {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/deep/ .el-range-separator {
  display: flex;
  justify-content: center;
}
.table-action {
  margin-right: 10px;
}

/deep/ .el-select__tags-text {
  display: inline-block;
  max-width: 40px;
  overflow: hidden;
  text-overflow:ellipsis;
  white-space: nowrap;
}
/deep/ .el-select .el-tag__close.el-icon-close {
  top: -7px;
  right: -4px;
}
.line {
  text-align: center;
}
.inner-form-item {
  margin-bottom: 0;
}
</style>
